package cn.yj.core.wechat;

import cn.yj.admin.ConsVal;
import cn.yj.api.FileUploadHandler;
import cn.yj.cgs.dba.entity.Customer;
import cn.yj.cgs.dba.entity.Integral;
import cn.yj.common.*;
import cn.yj.commons.StringPools;
import cn.yj.commons.utils.CheckUtils;
import cn.yj.commons.utils.MapUtils;
import cn.yj.commons.utils.StringUtils;
import cn.yj.config.annotation.Anonymous;
import cn.yj.config.web.AppBaseController;
import cn.yj.core.business.service.CustomerService;
import cn.yj.core.business.service.iservice.IIntegralService;
import cn.yj.entity.ByteEntity;
import cn.yj.entity.InputStreamEntity;
import cn.yj.entity.R;
import cn.yj.syslog.common.OperateLog;
import cn.yj.tools.exception.ServiceException;
import cn.yj.wechat.entity.WXEntity;
import cn.yj.wechat.miniprogram.IWxMinilService;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 永健
 * @since 2021-04-20 16:37
 */
@RestController
@RequestMapping("/wx")
public class AuthController extends AppBaseController {

    private static final Logger log = LoggerFactory.getLogger(AuthController.class);

    @Resource
    IWxMinilService wxMiniService;

    @Resource
    CustomerService customerService;

    @Resource
    IIntegralService integralService;

    private static WxHttpRequest http = new WxHttpRequest();

    /**
     * 授权获取openid 和手机号
     * 第一步先授权获取手机号
     * 第二步先授权获取昵称信息
     *
     * @param authModel
     */
    @Transactional
    @Anonymous
    @PostMapping("/toAuth")
    public R toAuth(@Valid @RequestBody AuthModel authModel) {
        WXEntity wxEntity;
        try {
            wxEntity = wxMiniService.getOpenId(authModel.getCode());

            int i = 0;
            Map<String, Object> stringObjectMap = null;
            while (i < 5 && StringUtils.isNull(stringObjectMap)) {
                try {
                    stringObjectMap = WechatDecryptDataUtil.encryUnionId(authModel.getEncryptedData(),
                            wxEntity.getSession_key(), authModel.getIv());
                } catch (Exception e) {
                }
                ++i;
            }
            if (StringUtils.isNull(stringObjectMap)) {
                return error("授权失败，请重试...");
            }

            String openid = wxEntity.getOpenid();

            String phoneNumber = MapUtils.getStringVal(stringObjectMap, "phoneNumber");
            Customer customer = customerService.getCustomByMiniOpenId(openid);
            if (StringUtils.isNotNull(customer)) {
                if (StringUtils.isBlank(customer.getNickName())) {
                    customer.setNickName(authModel.getNickName());
                    customer.setRealName(authModel.getNickName());

                }
                if (StringUtils.isBlank(customer.getUserPhone()) || !CheckUtils.isChinaPhoneLegal(customer.getUserPhone())) {
                    if (StringUtils.isNotBlank(phoneNumber)) {
                        customer.setAvatar(authModel.getAvatar());
                        customer.setUserPhone(phoneNumber);
                    }
                }
                customerService.update(customer, new UpdateWrapper<Customer>().lambda().eq(Customer::getUserCode,
                        customer.getUserCode()));
                return success(MapUtils.beanToMapFilterNull(customer));
            }
            customer = new Customer();
            customer.setMiniOpenId(openid);
            customer.setUserPhone(phoneNumber);
            customer.setCity(authModel.getCity());
            customer.setNickName(authModel.getNickName());
            customer.setRealName(customer.getNickName());
            customer.setAvatar(StringUtils.isBlank(customer.getAvatar())?authModel.getAvatar():customer.getAvatar());
            customerService.save(customer);

            // 邀请码 重复检测
            String inviteCode = InviteCode.instance().gen(Long.parseLong(String.valueOf(customer.getId())));
            int count = 50;
            while (StringUtils.isBlank(checkCode(inviteCode)) && count > 0) {
                inviteCode = UUIdUtils.getCode();
                ++count;
            }

            if (StringUtils.isBlank(inviteCode)) {
                log.error("邀请码生成失败，生成50次都存在重复");
                return error("授权失败,请重试...");
            }

            ByteArrayOutputStream qrGen = QrUtils.createQrGen(inviteCode);

            ByteEntity byteEntity = new ByteEntity(qrGen.toByteArray(),
                    Enums.Minio.Bucket.qrcode.name().concat("/").concat(openid.concat(StringPools.JPG)));
            byteEntity.setContentType(Enums.Minio.ContentType.IMG.getContentType());

            String codeUrl = FileUploadHandler.getInstant().upload(byteEntity);

            customer.setInviteQrCode(codeUrl);
            customer.setInviteCode(inviteCode);

            if (StringUtils.isNotBlank(authModel.getAvatar())) {
                Customer finalCustomer = customer;
                AppExecutor.exec(() -> {
                    try {
                        InputStream inputStream = http.httpSendGetFile(authModel.getAvatar(), new HashMap<>());

                        InputStreamEntity entity = new InputStreamEntity(inputStream,
                                Enums.Minio.Bucket.avatar.name().concat("/").concat(ConsVal.AVATAR_PREFIX.concat(finalCustomer.getUserCode()).concat(StringPools.JPG)));
                        entity.setContentType(Enums.Minio.ContentType.IMG.getContentType());

                        String upload = FileUploadHandler.getInstant().upload(entity);

                        customerService.update(new Customer().setUserCode(finalCustomer.getUserCode()).setAvatar(upload), new UpdateWrapper<Customer>().lambda().eq(Customer::getUserCode, finalCustomer.getUserCode()));
                    } catch (Exception e) {
                        log.error("头像处理异常,{}", e.getMessage());
                    }
                });
            }

            String userCode = getUserCode(customer.getId());
            if (customerService.exitsByUserCode(userCode)) {
                userCode = UUIdUtils.getCode();
            }
            customer.setUserCode(userCode);

            customerService.update(customer, new UpdateWrapper<Customer>().lambda().eq(Customer::getMiniOpenId,
                    customer.getMiniOpenId()));

            // 创建积分账户
            integralService.save(new Integral(customer.getUserCode()));

            return success(MapUtils.beanToMapFilterNull(customer));
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("授权失败，请重试...");
        }
    }

    private String getUserCode(Integer id) {
        String userCode = InviteCode.instance().gen(8, Long.parseLong(String.valueOf(id)));
        int count = 10;
        while (customerService.exitsByUserCode(userCode) && count > 0) {
            userCode = InviteCode.instance().gen(8, Long.parseLong(String.valueOf(id)));
            --count;
        }
        return userCode;
    }

    private String checkCode(String code) {
        if (customerService.exitsByInviteCode(code)) {
            return null;
        }
        return code;
    }
}
